package me.zhengjie.config.sftp;

import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;

@Configuration
@Slf4j
public class SftpConfig {

    private final SftpConnector connector;

    public SftpConfig(SftpConnector connector) {
        this.connector = connector;
    }

    /**
     * 创建并预热 SFTP 连接池，所有参数通过 @Value 注入：
     * - maxTotal：池中最大连接数
     * - minIdle：最小空闲连接数
     * - testOnBorrow / testWhileIdle：借用/空闲时校验
     * - evictionInterval：空闲连接驱逐线程间隔（秒）
     */
    @Bean
    public GenericObjectPool<ChannelSftp> sftpPool(
            @Value("${sftp.pool.max-total:20}") int maxTotal,
            @Value("${sftp.pool.min-idle:5}") int minIdle,
            @Value("${sftp.pool.test-on-borrow:true}") boolean testOnBorrow,
            @Value("${sftp.pool.test-while-idle:true}") boolean testWhileIdle,
            @Value("${sftp.pool.time-between-eviction-runs-seconds:30}") long evictionIntervalSeconds) {

        // 1. 配置连接池参数
        GenericObjectPoolConfig<ChannelSftp> config = new GenericObjectPoolConfig<>();
        config.setMaxTotal(maxTotal);                                           // 设置最大连接数 :contentReference[oaicite:3]{index=3}
        config.setMinIdle(minIdle);                                             // 设置最小空闲连接数 :contentReference[oaicite:4]{index=4}
        config.setTestOnBorrow(testOnBorrow);                                   // 借用前校验 :contentReference[oaicite:5]{index=5}
        config.setTestWhileIdle(testWhileIdle);                                 // 空闲时校验 :contentReference[oaicite:6]{index=6}
        config.setTimeBetweenEvictionRuns(Duration.ofSeconds(evictionIntervalSeconds)); // 驱逐线程间隔（秒） :contentReference[oaicite:7]{index=7}
        config.setJmxEnabled(false);

        // 2. 创建连接池
        GenericObjectPool<ChannelSftp> pool = new GenericObjectPool<>(
                new BasePooledObjectFactory<ChannelSftp>() {

                    @Override
                    public ChannelSftp create() throws Exception {
                        Session session = connector.createSession();
                        // 可根据需要配置加密和压缩
                        session.setConfig("cipher.s2c", "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com");
                        session.setConfig("compression.s2c", "zlib@openssh.com,zlib");
                        session.setConfig("compression.c2s", "zlib@openssh.com,zlib");
                        return connector.createChannel(session);
                    }

                    @Override
                    public PooledObject<ChannelSftp> wrap(ChannelSftp obj) {
                        return new DefaultPooledObject<>(obj);
                    }

                    @Override
                    public boolean validateObject(PooledObject<ChannelSftp> p) {
                        try {
                            return p.getObject().isConnected()
                                    && p.getObject().getSession().isConnected();
                        } catch (Exception e) {
                            return false;
                        }
                    }

                    @Override
                    public void destroyObject(PooledObject<ChannelSftp> p) {
                        try {
                            p.getObject().disconnect();
                            if (p.getObject().getSession() != null) {
                                p.getObject().getSession().disconnect();
                            }
                        } catch (Exception e) {
                            log.error("Destroy SFTP connection failed", e);
                        }
                    }
                },
                config
        );                                                                       // 使用指定配置创建连接池 :contentReference[oaicite:8]{index=8}

        // 3. 预热连接池
        try {
            pool.preparePool();                                                      // 预创建 minIdle 个空闲连接 :contentReference[oaicite:9]{index=9}
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 4. 输出预热结果
        log.info("SFTP 连接池预热完成：minIdle={}，当前空闲连接数={}", minIdle, pool.getNumIdle());

        return pool;
    }
}
